package com.zmn.oms.business.impl.work.distribute;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.google.common.collect.Lists;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.consts.GlobalConsts;
import com.zmn.manager.mq.constant.MqTopicConsts;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.business.interfaces.callinfo.CallInfoBService;
import com.zmn.oms.business.interfaces.messageV1.SendOrderMessageService;
import com.zmn.oms.business.interfaces.messageV1.common.MessageSendBaseService;
import com.zmn.oms.business.interfaces.order.DuplicateOrderBService;
import com.zmn.oms.business.interfaces.work.distribute.DistributeTimeoutBservice;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.manager.utils.OmsMqTagConsts;
import com.zmn.oms.model.dto.messageV1.SendMessageRespDTO;
import com.zmn.oms.model.dto.timeout.DistributeTimeoutDTO;
import com.zmn.oms.model.dto.work.call.CallOutDTO;
import com.zmn.oms.model.entity.changerecord.OrderChangeRecord;
import com.zmn.oms.model.entity.conf.channel.ConfOrderChannel;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.changerecord.OrderChangeRecordService;
import com.zmn.oms.services.interfaces.conf.channel.ConfOrderChannelService;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.product.OrderProductService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.track.common.constant.TrackConfigConsts;
import com.zmn.track.common.constant.TrackConsts;
import com.zmn.track.dubbo.dto.TrackWorkDIO;
import com.zmn.track.dubbo.dto.TrackWorkQuery;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkListRemoteService;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkModifyRemoteService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 类描述：派单超时检查
 *
 * @author liuying
 * @date 2018/11/02 21:02
 */
@Service
@Slf4j
public class DistributeTimeoutBServiceImpl implements DistributeTimeoutBservice {

    @Autowired
    OrderWorkService orderWorkService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private ZmnMQSender zmnMQSender;
    @Autowired
    private CallInfoBService callInfoBService;
    @Autowired
    private SendOrderMessageService sendOrderMessageService;
    @Autowired
    private MessageSendBaseService messageSendBaseService;
    @Autowired
    OrderProductService orderProductService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private RedisManager redisManager;
    @Autowired
    private OrderChangeRecordService orderChangeRecordService;
    @Autowired
    private DuplicateOrderBService duplicateOrderBService;
    @Resource
    private ConfOrderChannelService confOrderChannelService;
    @Value("${spring.profiles.active}")
    private String active;


    @DubboReference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkModifyRemoteService trackWorkModifyRemoteService;
    @DubboReference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkListRemoteService trackWorkListRemoteService;

    /**
     * 派单超时用户确认 url
     */
//    @Value("${oms.h5.distribute.timeout.url:http://test2-h5.xiujiadian.com/wxuser/brand/#/subPackages/order/detail/index?id=%s&origin=sms}")
//    private String distributeTimeoutUrl;
    @NacosValue(value = "${enable.autoDistributeTimeoutCheck:true}", autoRefreshed = true)
    private boolean autoDistributeTimeoutCheck = true;

    @NacosValue(value = "${oms.autoDistributeTimeoutCheckDeliverTime:60}", autoRefreshed = true)
    private Integer deliverTime = 60;

//    @NacosValue(value = "${oms.non.cancel.directly.channel.id:}", autoRefreshed = true)
//    private String nonCancelDirectlyChannels;

    @Override
    public void addTimeoutCheck(Long orderId, Long workId) {
        log.info("开始发起派单超时检查: orderId={} workId={}", orderId, workId);
        if (!autoDistributeTimeoutCheck) {
            log.info("开始发起派单超时检查-跳过: orderId={} workId={}", orderId,workId);
            return;
        }
        // 查询工单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        // 只有啄木鸟平台
        if (!Objects.equals(orderWork.getPlatWork(), GlobalConsts.PLAT_MARK_ZMN)) {
            return;
        }
        // 非新单不处理
        if (!Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_NEW)) {
            return;
        }
        if (Objects.isNull(orderWork.getDutyTime())) {
            return;
        }
//        （2）预约时间在当天7:30前：从07:30预约时间开始计时
//        （3）预约时间在当天（7:30~21:30）：从下单时间开始计时
//        （4）预约时间在 [21:30~07:30]：从第二天07:30开始计时
//        （5）预约时间为第二天（7:30~12:00] ：从预约时间开始计时
//        （6）预约时间在第二天12:00后：不通知

        // 下单时间
        LocalDateTime receiveTime = LocalDateTime.ofInstant(orderWork.getReceiveTime().toInstant(), ZoneId.systemDefault());
        // 预约时间
        LocalDateTime dutyTime = LocalDateTime.ofInstant(orderWork.getDutyTime().toInstant(), ZoneId.systemDefault());
        // 当天凌晨
        LocalDateTime zeroTime = LocalDateTime.of(orderWork.getReceiveTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), LocalTime.MIN);
        // 当天 7:30
        LocalDateTime start = zeroTime.plusHours(7).plusMinutes(30);
        // 当天 21:30
        LocalDateTime end = zeroTime.plusHours(21).plusMinutes(30);
        // 第二天12:00
        LocalDateTime nextDay12d = zeroTime.plusDays(1).plusHours(12);
        // 第二天7:30
        LocalDateTime nextDay7d = zeroTime.plusDays(1).plusHours(7).plusMinutes(30);

        // 预约时间在第二天12:00后不处理
        if (dutyTime.isAfter(nextDay12d)) {
            return;
        }
        // 配置的延迟检查时间
        // Integer deliverTime = this.getDeliverTimeConfigure();
        // 检查时间 默认录单时间是工作时间从下单时间后1小时开始
        LocalDateTime checkTime = receiveTime.plusMinutes(deliverTime);
        if (receiveTime.isBefore(start) || receiveTime.equals(start)) {
            // 录单时间不在工作时间，按预约时间算
            checkTime = dutyTime.plusMinutes(deliverTime);
        }
        if (dutyTime.isBefore(start) || dutyTime.equals(start)) {
            // 预约时间在当天7:30之前，按预约时间算
            checkTime = start.plusMinutes(deliverTime);
        }
        if ((dutyTime.isAfter(end) && dutyTime.isBefore(nextDay7d)) || dutyTime.equals(end) || dutyTime.equals(nextDay7d)) {
            // 第二天 7:30 + 1 小时
            checkTime = nextDay7d.plusMinutes(deliverTime);
        } else if (dutyTime.isAfter(nextDay7d)) {
            // 预约时间为第二天[7:30~12:00]
            // 预约时间 + 1 小时
            checkTime = dutyTime.plusMinutes(deliverTime);
        }

        String message = JSON.toJSONString(BeanMapper.map(orderWork, DistributeTimeoutDTO.class));
        String keyMQ = "oms_distribute_timeout_check_" + orderWork.getOrderId();
        log.info("派单超时异步检查: orderId={} workId={} 检查时间：{}", orderId, workId, checkTime);
        zmnMQSender.sendWithStartDeliverTime(MqTopicConsts.ZMN_TOPIC_OMS, OmsMqTagConsts.ZMN_TOPIC_OMS_DISTRIBUTE_TIMEOUT_CHECK, keyMQ, message, Timestamp.valueOf(checkTime).getTime());
    }

    @Override
    public void timeoutCheck(DistributeTimeoutDTO distributeTimeoutDTO) {
        // 避免重复消费
        String redisKey = String.format(RedisKeyConsts.ORDER_DISTRIBUTE_TIMEOUT_CHECK_KEY, distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getDutyTime());
        if (redisManager.exists(redisKey)) {
            log.info("{}派单超时检查重复消费: orderId={} workId={}", LocalDateTime.now(), distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId());
            return;
        }

        // 添加已处理标志
        redisTemplate.opsForValue().set(redisKey, String.valueOf(GlobalConsts.YES), 60, TimeUnit.MINUTES);

        /*
          （1）工单状态：已录入 || 已确认 || 已分单
          （2）夜间抢单：不通知
          （3）存在：待处理 || 处理中的 & 跟单类型：非“系统发起跟单”：不通知
         */
        log.info("派单超时检查: orderId={} workId={}", distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId());
        if (!autoDistributeTimeoutCheck) {
            log.info("派单超时检查-跳过: orderId={} workId={}", distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId());
            return;
        }

        // 查询工单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKeySrcMaster(distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId());
        if (Objects.isNull(orderWork)) {
            return;
        }

        // 预约时间发生变更
        if (!Objects.equals(orderWork.getDutyTime(), distributeTimeoutDTO.getDutyTime())) {
            // 预约时间
            LocalDateTime dutyTime = LocalDateTime.ofInstant(orderWork.getDutyTime().toInstant(), ZoneId.systemDefault());
            LocalDateTime end = LocalDateTime.of(orderWork.getReceiveTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), LocalTime.MIN).plusHours(21).plusMinutes(30);
            if (dutyTime.equals(end) || dutyTime.isAfter(end)) {
                log.info("预约时间发生变更:{}=>{},重新发起派单超时检查: orderId={} workId={}", distributeTimeoutDTO.getDutyTime(), distributeTimeoutDTO.getDutyTime(), distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId());
                this.addTimeoutCheck(distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId());
                return;
            }
        }

        // 已确认 || 已分单
        if (!(Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_CONFIRM) ||
                Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_ASSIGN))) {
            return;
        }

        // 不自动派单
        if (!Objects.equals(orderWork.getAutoDistribute(), GlobalConsts.YES)) {
            return;
        }

        // 抢单订单，工单取消，工单挂起不做处理
        if (Objects.equals(orderWork.getGrabType(), OrderConsts.ORDER_GRAB_TYPE_GRAB) ||
                !Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING) ||
                Objects.equals(orderWork.getDutyStatus(), OrderDutyConsts.DUTY_STATUS_SUSPEND)) {
            return;
        }

        // 房屋业务
        if (Objects.equals(orderWork.getServCategId(), ProductConsts.SERV_CATEG_WATERPROOF) ||
                Objects.equals(orderWork.getServCategId(), ProductConsts.SERV_CATEG_METOPE) ||
                Objects.equals(orderWork.getServCategId(), ProductConsts.SERV_CATEG_KITCHEN_TOILET)) {
            return;
        }

        // 特殊渠道
        ConfOrderChannel confOrderChannel = confOrderChannelService.findByKey(orderWork.getChannelId());
        if (Objects.nonNull(confOrderChannel) && Objects.equals(confOrderChannel.getSupportBacktracking(), GlobalConsts.NO)) {
            return;
        }

        // 重复 & 源单 ＜ 已上门
        Long duplicateOrderId = duplicateOrderBService.findDistributeTimeoutDuplicateOrderId(orderWork);
        if (NumberUtil.isNotNullOrZero(duplicateOrderId)) {
            OrderWork originalWork = orderWorkService.findOrderWorkByKey(duplicateOrderId, duplicateOrderId);
            if (Objects.nonNull(originalWork) && originalWork.getStatus() < OrderStatusConsts.WORK_STATUS_VISIT) {
                log.info("派单超时检查: workId={} 原单：workId={}", orderWork, originalWork);
                return;
            }
        }

        // 订单详情
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderWork.getOrderId());

        // 行政服务商是无法承接线索
        if (Objects.equals(orderDetail.getGridManageCompanyId(), CompanyConsts.ZMN_UNABLE_SERVICE_MANAGE_COMPANY_ID)) {
            return;
        }

        // 派单撤回不处理
        OrderChangeRecord changeRecordByOrder = orderChangeRecordService.getChangeRecordByOrderId(distributeTimeoutDTO.getOrderId());
        if (Objects.nonNull(changeRecordByOrder) &&
                Objects.nonNull(changeRecordByOrder.getFirstDistributeTime())) {
            log.info("派单超时检查: orderId={} workId={} 派单撤回不处理,首次派单时间{}", distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId(), changeRecordByOrder.getFirstDistributeTime());
            return;
        }

        // 派单跟单存在待处理,处理中的人工跟单记录
        TrackWorkQuery query = new TrackWorkQuery();
        query.setOrderId(distributeTimeoutDTO.getOrderId());
        query.setWorkId(distributeTimeoutDTO.getWorkId());
        query.setNotStatus(TrackConsts.TRACK_STATUS_FINISHED);
        query.setPromoterTypeList(Lists.newArrayList(com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_USER,
                com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_STAFF,
                com.zmn.common.constant.GlobalConsts.OPERATE_USER_TYPE_MASTER));
        ResponseDTO<Integer> listResponseDTO = trackWorkListRemoteService.countTrackByQuery(query);
        log.info("派单超时检查: orderId={} workId={} 查询跟单存在人工跟单记录：{}", distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId(), listResponseDTO);
        if (!listResponseDTO.isSuccess()) {
            return;
        }
        if (Objects.nonNull(listResponseDTO.getData()) && listResponseDTO.getData() > 0) {
            return;
        }
        // 是否检查用户操作标志
        boolean sendFlag = false;
        // 发送短信
        try {
            SendMessageRespDTO sendMessageRespDTO = new SendMessageRespDTO();
            sendMessageRespDTO.setNodeMark(MessageConsts.ZMN_MSG_RULEID_DISTRIBUTE_TIMEOUT_CONFIRM);
            sendMessageRespDTO.setOrderId(orderWork.getOrderId());
            sendMessageRespDTO.setWorkId(orderWork.getWorkId());
            sendMessageRespDTO.setPlat(Optional.ofNullable(orderWork.getPlatWork()).orElse(orderWork.getPlat()));
            boolean isSendMessage = sendOrderMessageService.sendOrderMessage(sendMessageRespDTO);
            log.info("派单超时检查：orderId={} task 发送订单ruleId={}消息结果：{}", orderWork.getWorkId(), sendMessageRespDTO.getNodeMark(), isSendMessage);
            sendFlag = isSendMessage;
        } catch (Exception e) {
            log.error("派单超时检查: orderId={} workId={} 派单超时发送短信通知用户失败{}", distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId(), e.getMessage());
            e.printStackTrace();
        }
        // 机器人电话
        try {
            log.info("派单超时检查: orderId={} workId={} 派单超时机器人电话通知用户", distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId());
            callInfoBService.callDistributeTimeoutRemind(BeanMapper.map(orderWork, CallOutDTO.class));
            sendFlag = true;
        } catch (OmsBaseException e) {
            log.error("派单超时检查: orderId={} workId={} 派单超时机器人电话通知用户失败{}", distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId(), e.getMessage());
            e.printStackTrace();
        }

        // 5分钟后检查用户是否操作
        if (!sendFlag) {
            return;
        }

        String message = JSON.toJSONString(distributeTimeoutDTO);
        String keyMQ = "oms_distribute_timeout_deal_check_" + distributeTimeoutDTO.getOrderId();
        zmnMQSender.sendWithStartDeliverTime(MqTopicConsts.ZMN_TOPIC_OMS, OmsMqTagConsts.ZMN_TOPIC_OMS_DISTRIBUTE_TIMEOUT_DEAL_CHECK, keyMQ, message, System.currentTimeMillis() + (10 * 60 * 1000));
    }


    @Override
    public void timeoutProcess(DistributeTimeoutDTO distributeTimeoutDTO) {

        String redisKey = String.format(RedisKeyConsts.ORDER_DEAL_DISTRIBUTE_TIMEOUT_KEY, distributeTimeoutDTO.getOrderId());
        if (redisManager.exists(redisKey)) {
            return;
        }

        log.info("派单超时发起跟单-入参：{}", JSON.toJSONString(distributeTimeoutDTO));

        // 查询工单信息
        OrderWork orderWork = orderWorkService.findOrderWorkByKeySrcMaster(distributeTimeoutDTO.getOrderId(), distributeTimeoutDTO.getWorkId());
        if (Objects.isNull(orderWork)) {
            return;
        }
        if (!Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING)) {
            return;
        }

        // 派单超时继续等待跟单
        TrackWorkDIO trackDIO = new TrackWorkDIO();
        trackDIO.setOrderId(orderWork.getOrderId());
        trackDIO.setWorkId(orderWork.getWorkId());
        trackDIO.setTrackContentId(TrackConfigConsts.TRACK_CONTENT_ID_DISTRIBUTE_TIMEOUT_WAIT);
        trackDIO.setReasonId(distributeTimeoutDTO.getReasonId());
        trackDIO.setOperator(distributeTimeoutDTO.getOperator());
        trackDIO.setOperatorId(distributeTimeoutDTO.getOperatorId());
        trackDIO.setOperatorType(distributeTimeoutDTO.getOperatorType());
        trackDIO.setOperatorLogRemark(distributeTimeoutDTO.getOperatorLogRemark());
        ResponseDTO responseDTO = trackWorkModifyRemoteService.addTrack(trackDIO);
        if (!responseDTO.isSuccess()) {
            log.info("派单超时发起跟单-处理失败，入参：{}，出参：{}", JSON.toJSONString(trackDIO), JSON.toJSONString(responseDTO));
            return;
        }

        // 添加已处理标志
        redisTemplate.opsForValue().set(redisKey, String.valueOf(GlobalConsts.YES), 1, TimeUnit.DAYS);
    }

    /**
     * 获取派单超时检查延时配置
     *
     * @return
     */
    @Override
    public Integer getDeliverTimeConfigure() {
//        BaseCodeMapDRO oneBaseCodeMap = baseCodeService.getOneBaseCodeMap(GlobalConsts.PLAT_MARK_ZMN, DistributeTimeoutConsts.BASE_CODE_MAP_ONE_TYPE_TIMEOUT_CHECK_TIME, DistributeTimeoutConsts.BASE_CODE_MAP_TWO_TIMEOUT_CHECK_TIME);
//        return oneBaseCodeMap.getThreeTypeId();
        return  deliverTime;
    }
}
